"""

token password 验证

pip install python-jose

pip install passlib


"""
import json
import re
import traceback
from datetime import datetime, timedelta
from typing import Any, Union

from jose import jwt
from passlib.context import CryptContext

from app.conf import settings
from fastapi.security import OAuth2PasswordBearer

from fastapi import Depends, Request

from app.db.session import SessionLocal
from app.models.system import Users
from app.utils.custom_exc import CustomException

pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
oauth2_scheme = OAuth2PasswordBearer(tokenUrl=f"{settings.API_V1_STR}/token")


def get_user(db, user_id):

    user = db.query(Users).filter(Users.id == user_id).first()
    return user


def create_token(subject: Union[str, Any]) -> dict:
    """
    创建token
    :param subject:
    :return:
    """

    access_expire = datetime.utcnow() + timedelta(
        seconds=settings.ACCESS_ACCESS_TOKEN_EXPIRE_MINUTES
    )
    to_encode = {"exp": access_expire, "sub": json.dumps({"user": subject, "type": 'access'})}
    access_encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.JWT_ALGORITHM)

    refresh_expire = datetime.utcnow() + timedelta(
        seconds=settings.ACCESS_ACCESS_TOKEN_EXPIRE_MINUTES
    )
    to_encode = {"exp": refresh_expire, "sub": json.dumps({"user": subject, "type": 'refresh'})}
    refresh_encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.JWT_ALGORITHM)
    token_dict = dict()
    token_dict['access_token'] = access_encoded_jwt
    token_dict['refresh_token'] = refresh_encoded_jwt
    return token_dict


def parse_token(token):
    """
    用于解密
    :param token:
    :return:
    """
    try:
        # 进行解密
        # token = bytes(token, 'utf-8')
        data = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.JWT_ALGORITHM])
        result = True
    except Exception as e:
        # print(traceback.format_exc())
        data = {}
        result = False
    return result, data


def verify_access_token(token: str = Depends(oauth2_scheme)):
    """
    验证token
    :param token:
    :return:
    """
    if token:
        # print(token, type(token))
        result, data = parse_token(token)
        if result:
            data = json.loads(data['sub'])
            if data.get('type') == 'access':
                db = SessionLocal()
                user = get_user(db, data['user'])
                # print(user)
                if user:
                    if user.is_active != 1:
                        raise CustomException("当前用户不可用", code=4001)
                    return user
                else:
                    raise CustomException("身份验证失败", code=4001)
            else:
                raise CustomException("身份验证失败", code=4001)
        else:
            raise CustomException("身份验证失败", code=4001)
    else:
        raise CustomException("身份验证失败", code=4001)


def verify_user_api_permission(request: Request, user: Users = Depends(verify_access_token)):
    """
    验证接口权限
    :param request:
    :param user:
    :return:
    """
    if user and user.is_superuser == 1:
        return user

    user_role_list = [ad.role.admin for ad in user.role]
    if True in user_role_list:
        return user

    role_list = [ad.role for ad in user.role]
    permission_list_list = [role.permission for role in role_list]
    permission_list = [permission.permission for permission_list in permission_list_list for permission in permission_list]
    api_method_list = [f"{permission.url.replace('{id}', '([a-zA-Z0-9-]+)')}:{permission.method}" for permission in permission_list]
    current_path = f"{str(request.url.path)}:{str(request.method)}"
    # print(api_method_list)
    # print(request.method, request.url.path, current_path)
    for item in api_method_list:
        matchObj = re.match(item, current_path, re.M | re.I)
        if matchObj:
            return user
    # if current_path in api_method_list:
    #     return user

    raise CustomException("用户无权限")


def verify_superadmin_permission(user: Users = Depends(verify_access_token)):
    """
    验证超级管理员
    :param user:
    :return:
    """
    if user and user.is_superuser == 1:
        return user
    else:
        raise CustomException("用户无权限")


def verify_admin_permission(user: Users = Depends(verify_access_token)):
    """
    验证管理员
    :param user:
    :return:
    """
    if user and user.is_superuser == 1:
        return user

    user_role_list = [ad.role.admin for ad in user.role]
    if True in user_role_list:
        return user

    raise CustomException("用户无权限")


def verify_password(plain_password: str, hashed_password: str) -> bool:
    return pwd_context.verify(plain_password, hashed_password)


def get_password_hash(password: str) -> str:
    return pwd_context.hash(password)
